将原始数组或字符串字面值传递给模板时，务必小心。若模板参数声明为引用，则参数不会衰变，传入的"hello"参数为char const[6]类型。若因类型不同而传递不同长度的原始数组或字符串参数，这可能会成为一个问题。只有当按值传递参数时，类型才会衰变，因此字符串字面值转换为char const*。这将在第7章中详细讨论。

注意，还可以提供专门处理原始数组或字符串字面量的模板。例如:

\hspace*{\fill} \\ %插入空行
\noindent
\textit{basics/lessarray.hpp}
\begin{lstlisting}[style=styleCXX]
template<typename T, int N, int M>
bool less (T(&a)[N], T(&b)[M])
{
	for (int i = 0; i<N && i<M; ++i) {
		if (a[i]<b[i]) return true;
		if (b[i]<a[i]) return false;
	}
	return N < M;
}
\end{lstlisting}

这里使用

\begin{lstlisting}[style=styleCXX]
int x[] = {1, 2, 3};
int y[] = {1, 2, 3, 4, 5};
std::cout << less(x,y) << '\n';
\end{lstlisting}

less<>()实例化，T为int，N为3，M为5。

也可以将此模板用于字符串字面值:

\begin{lstlisting}[style=styleCXX]
std::cout << less("ab","abc") << '\n';
\end{lstlisting}

这种情况下，less<>()实例化，T为char const，N为3，M为4。

若想为字符串(和其他字符数组)提供一个函数模板，可以这样:

\hspace*{\fill} \\ %插入空行
\noindent
\textit{basics/lessstring.hpp}
\begin{lstlisting}[style=styleCXX]
template<int N, int M>
bool less (char const(&a)[N], char const(&b)[M])
{
	for (int i = 0; i<N && i<M; ++i) {
		if (a[i]<b[i]) return true;
		if (b[i]<a[i]) return false;
	}
	return N < M;
}
\end{lstlisting}

注意，对于边界未知的数组，可以(有时必须)重载或偏特化。下面的代码演示了数组所有可能的重载:

\hspace*{\fill} \\ %插入空行
\noindent
\textit{basics/arrays.hpp}
\begin{lstlisting}[style=styleCXX]
#include <iostream>

template<typename T>
struct MyClass; // primary template

template<typename T, std::size_t SZ>
struct MyClass<T[SZ]> // partial specialization for arrays of known bounds
{
	static void print() { std::cout << "print() for T[" << SZ << "]\n"; }
};

template<typename T, std::size_t SZ>
struct MyClass<T(&)[SZ]> // partial spec. for references to arrays of known bounds
{
	static void print() { std::cout << "print() for T(&)[" << SZ << "]\n"; }
};

template<typename T>
struct MyClass<T[]> // partial specialization for arrays of unknown bounds
{
	static void print() { std::cout << "print() for T[]\n"; }
};

template<typename T>
struct MyClass<T(&)[]> // partial spec. for references to arrays of unknown bounds
{
	static void print() { std::cout << "print() for T(&)[]\n"; }
};

template<typename T>
struct MyClass<T*> // partial specialization for pointers
{
	static void print() { std::cout << "print() for T*\n"; }
};
\end{lstlisting}

类模板MyClass<>用于各种类型:已知和未知边界的数组、对已知和未知边界的数组的引用，以及指针。每种情况都不同，可以在使用数组时产生:

\hspace*{\fill} \\ %插入空行
\noindent
\textit{basics/arrays.cpp}
\begin{lstlisting}[style=styleCXX]
#include "arrays.hpp"

template<typename T1, typename T2, typename T3>
void foo(int a1[7], int a2[], // pointers by language rules
		int (&a3)[42], // reference to array of known bound
		int (&x0)[], // reference to array of unknown bound
		T1 x1, // passing by value decays
		T2& x2, T3&& x3) // passing by reference
{
	MyClass<decltype(a1)>::print(); // uses MyClass<T*>
	MyClass<decltype(a2)>::print(); // uses MyClass<T*>
	MyClass<decltype(a3)>::print(); // uses MyClass<T(&)[SZ]>
	MyClass<decltype(x0)>::print(); // uses MyClass<T(&)[]>
	MyClass<decltype(x1)>::print(); // uses MyClass<T*>
	MyClass<decltype(x2)>::print(); // uses MyClass<T(&)[]>
	MyClass<decltype(x3)>::print(); // uses MyClass<T(&)[]>
}

int main()
{
	int a[42];
	MyClass<decltype(a)>::print(); // uses MyClass<T[SZ]>
	
	extern int x[]; // forward declare array
	MyClass<decltype(x)>::print(); // uses MyClass<T[]>
	foo(a, a, a, x, x, x, x);
	
}

int x[] = {0, 8, 15}; // define forward-declared array
\end{lstlisting}

注意，由语言规则声明为数组(带或不带长度)的调用参数实际上具有指针类型。未知边界的数组模板可以用于不完整类型，例如

\begin{lstlisting}[style=styleCXX]
extern int i[];
\end{lstlisting}

当通过引用传递时，就变成了一个int(\&)[]，也可以用作模板参数。

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}类型X(\&)[]——对于某些任意类型X——参数仅在C++17中有效，通过核心问题393的解决。在语言的早期版本中，许多编译器也可以接受这样的参数。
\end{tcolorbox}

泛型代码中使用不同数组类型的另一种例子可参见19.3.1节。

















